package com.dm.cloud.tkmybatis.service;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.dm.cloud.basepo.po.BasePo;
import com.dm.cloud.core.mode.BaseDTO;
import com.dm.cloud.core.mode.PageList;
import com.dm.cloud.core.mode.ResultModel;
import com.dm.cloud.core.mode.SearchRequestPage;
import com.dm.cloud.core.service.user.CurrentUserService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 基础controller
 *
 * @author Administrator
 * @date 2022年 05月13日 13:37:37
 */
@Slf4j
public abstract class EntityBaseController<P extends SearchRequestPage, T extends BasePo, D extends BaseDTO> extends BaseController {

    public enum FunctionEnum{
        pageList("pageList"),
        detail("detail"),
        insert("insert"),
        update("update"),
        deleteById("deleteById"),
        deleteBatchIds("deleteBatchIds"),
        idsList("idsList");
        private String functionName;
        FunctionEnum(String functionName){
            this.functionName=functionName;
        }
        public String getValue(String functionName){
            return this.functionName;
        }
        public static boolean hashEnumByName(String functionName){
            for (FunctionEnum value : FunctionEnum.values()) {
                if(value.functionName.equals(functionName)){
                    return true;
                }
            }
            return false;
        }
        public static FunctionEnum getEnum(String functionName){

            return FunctionEnum.valueOf(functionName);
        }
    }

    private List<String> apiIgnoreFunctionName=new ArrayList<>();

    /**
     * 获取方法名字符串
     * @return
     */
    public boolean isIgnoreFunction(String functionName){
        return apiIgnoreFunctionName.contains(functionName);
    }


    @PostConstruct
    public void init(){
        List<FunctionEnum> apiIgnoreFunction = apiIgnoreFunction();
        if(!apiIgnoreFunction.isEmpty()){
            for (Method declaredMethod : this.getClass().getMethods()) {
                if(FunctionEnum.hashEnumByName(declaredMethod.getName()) && apiIgnoreFunction.contains(FunctionEnum.getEnum(declaredMethod.getName()))){
                    apiIgnoreFunctionName.add(declaredMethod.getName());
                }
            }
        }
    }

    /**
     * 要在swagger中排除的默认接口，通过重写实现
     * @return
     */
    public List<FunctionEnum> apiIgnoreFunction(){
        return new ArrayList<>();
    }

    @Autowired
    public CurrentUserService currUserService;

    /**
     * 获取实际服务类
     *
     * @return
     */
    public abstract BaseEntityService<P, T> getService();

    /**
     * 获取当前Controller数据库实体Entity
     *
     * @return
     */
    public abstract T getEntity();

    /**
     * 获取当前Controller数据传输DTO
     *
     * @return
     */
    public abstract D getDTO();

    /**
     * 分页模板
     *
     * @param param
     * @return
     */
    @PostMapping("/pageList")
    @Operation(summary = "【默认】分页查询数据")
    public ResultModel<PageList<D>> pageList(@RequestBody P param) {
        PageList<T> pagelist = getService().page(param);
        List<T> records = pagelist.getData();

        //entity转换成DTO
        List<D> list = (List<D>) BeanUtil.copyToList(records, getDTO().getClass());

        //处理dto返回结果
        pageResultHandler(list);
        PageList<D> reList=new PageList<D>();
        reList.setData(list);
        reList.setPageParam(pagelist.getPageParam());
        return responseSuccessWithData(reList);
    }

    /**
     * 对分页dto返回处理
     * @param list
     * @return
     */
    public List<D> pageResultHandler(List<D> list) {
        return list;
    }

    /**
     * 对详情返回DTO进行处理
     * @param detail
     * @return
     */
    public D detailResultHandler(D detail) {
        return detail;
    }


    public List<D> poToDto(List<T> pos){
        if(pos==null || pos.isEmpty()){
            return new ArrayList<>();
        }
        return (List<D>) BeanUtil.copyToList(pos, getDTO().getClass());
    }

    public D poToDto(T po){
        if(po==null){
            return null;
        }
        return (D) BeanUtil.toBean(po,getDTO().getClass());
    }
    /**
     * 根据ID查询相关记录
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @Operation(summary = "【默认】查询单条数据详情")
    public ResultModel<D> detail(@PathVariable("id") String id) {
        log.info("{}根据ID查询服务开始，id为：{}", this.getClass().getSimpleName(), id);
        T result = getService().selectOne(id);

        D dto = getDTO();
        dto= (D) BeanUtil.toBean(result,dto.getClass());

        //对返回值建处理
        detailResultHandler(dto);
        ResultModel<D> responseBean = responseSuccessWithData(resultDtoHandle(dto));
        log.info("{}根据ID查询结束，结果：{}", this.getClass().getSimpleName(), JSON.toJSONString(responseBean));
        return responseBean;
    }

    /**
     * 对明细结果进行处理,子类可以覆盖
     * @param d
     * @return
     */
    protected D resultDtoHandle(D d) {
        return d;
    }

    /**
     * 插入
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PostMapping
    @Operation(summary = "【默认】插入一条数据")
    public ResultModel insert(@Validated @RequestBody D dto) {
        log.info("{}新增服务开始，参数：{}", this.getClass().getSimpleName(), JSON.toJSONString(dto));
        T entity = getEntity();
        //dto转为数据库实体
        BeanUtils.copyProperties(dto, entity);
        //插入
        getService().insert(entity);
        BeanUtils.copyProperties(entity,dto);
        ResultModel responseBean = responseSuccessWithData(dto);
        log.info("{}新增服务结束，结果：{}", this.getClass().getSimpleName(), JSON.toJSONString(responseBean));
        return responseBean;
    }

    /**
     * 根据ID修改对饮记录
     *
     * @param dto
     * @return
     * @throws Exception
     */
    @PutMapping
    @Operation(summary = "【默认】更新一条数据")
    public ResultModel update(@Validated @RequestBody D dto) {
        String username = currUserService.uname();
        log.info("{}更新服务开始,更新人：{}，参数：{}", this.getClass().getSimpleName(), username, JSON.toJSONString(dto));
        T entity = getEntity();
        //dto转换entity
        BeanUtils.copyProperties(dto, entity);

        getService().update(entity);

        log.info("{}更新服务结束，结果：{}", this.getClass().getSimpleName(), JSON.toJSONString(entity));

        return responseSuccess();
    }


    /**
     * 根据ID删除指定记录,这里被删除的记录会进入删除记录表
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "【默认】删除一条数据")
    public ResultModel deleteById(@PathVariable("id") String id) {
        log.info("{}删除服务开始，参数ID：{}", this.getClass().getSimpleName(), id);
        getService().deleteById(id);
        log.info("{}删除服务结束", this.getClass().getSimpleName());
        return responseSuccess();
    }

    /**
     * 删除批量ID对应的记录
     *
     * @param ids
     * @return
     */
    @PostMapping("/delete/batch")
    @Operation(summary = "【默认】批量删除数据")
    public ResultModel<Integer> deleteBatchIds(@RequestBody List<Serializable> ids) {
        log.info("{}批量删除服务开始，批量参数Ids：{}", this.getClass().getSimpleName(), JSON.toJSONString(ids));
        Integer deleteCount = getService().deleteByIds(ids);
        ResultModel<Integer> responseBean= responseSuccessWithData(deleteCount);
        log.info("{}批量删除服务结束，结果：{}", this.getClass().getSimpleName(), JSON.toJSONString(responseBean));
        return responseBean;
    }

    /**
     * 根据ID查询数据列表
     * @param ids
     * @return
     */
    @PostMapping("/idsList")
    @Operation(summary = "【默认】根据ID批量查询数据")
    public ResultModel<List<D>> idsList(@RequestBody List<String> ids) {
        log.info("{}批量查询服务开始，批量参数Ids：{}", this.getClass().getSimpleName(), JSON.toJSONString(ids));
        List<T> datas= getService().selectByIds(ids);
        //entity转换成DTO
        List<D> list = (List<D>) BeanUtil.copyToList(datas, getDTO().getClass());
        //处理dto返回结果
        pageResultHandler(list);
        ResultModel<List<D>> responseBean= responseSuccessWithData(list);
        log.info("{}批量查询服务结束，结果：{}", this.getClass().getSimpleName(), JSON.toJSONString(responseBean));
        return responseBean;
    }

}
